﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;

namespace Scope8
{
    /// <summary>
    /// Diese Klasse reprässentiert ein Slide des Chariteservers. Ein Slide ist nach unseren Vorstellungen ein Objekt, das einem Bild sehr ähnlich kommt. Es wird aber zusätlich von einem 
    /// Web-Slide-Server abgefragt, der eine bestimmte Auflösung anhand der Abfrageparamter ermittelt.
    /// </summary>
    class ChariteSlide : Slide
    {
        /// <summary>
        /// das Zielverhältnis von Höhe druch Breite. HW= höhe durch breite WH=breite durch höhe
        /// </summary>
        private double targetRatio_HW = 0;
        /// <summary>
        /// das Zielverhältnis von Breite druch Höhe. HW= höhe durch breite WH=breite durch höhe
        /// </summary>
        private double targetRatio_WH = 0;
        /// <summary>
        /// das Slideverhältnis von Höhe druch Breite. HW= höhe durch breite WH=breite durch höhe
        /// </summary>
        private double slideRatio_HW = 0;
        /// <summary>
        /// das Slideverhältnis von Breite druch Höhe. HW= höhe durch breite WH=breite durch höhe
        /// </summary>
        private double slideRatio_WH = 0;

        /// <summary>
        /// skalierte Breite des Bildausschnitts34)
        /// </summary>
        private int scrw = 0;
        /// <summary>
        /// skalierte Höhe des Bildausschnitts34)
        /// </summary>
        private int scrh = 0;
        /// <summary>
        /// Breite des Bildausschnitts
        /// </summary>
        private int slidew = 0;
        /// <summary>
        /// Höhe des Bildausschnitts
        /// </summary>
        private int slideh = 0;
        /// <summary>
        /// linke Kante des Bildausschnitts: 0 … gesamte Breite - slidew/2
        /// </summary>
        private int posX = 0;
        /// <summary>
        /// 
        /// obere Kante des Bildausschnitts: 0 … gesamte Höhe - slideh/2
        /// </summary>
        private int posY = 0;


        /// <summary>
        /// Initialisiert eine Instanz der Klasse.
        /// </summary>
        public ChariteSlide()
            : base()
        {
            setServerURL(ChariteConstants.chariteUrl_pure);
            setThumbNails("?scrw=250&scrh=250");
        }

        //// <summary>
        /// Erzeugt eine Instanz der Klasse mit den angegebenen Werten
        /// </summary>
        /// <param name="newPicName">der Bildname</param>
        /// <param name="newWidth">die max. Breite des Bildes</param>
        /// <param name="newHeight">die max. Höhe des Bildes</param>
        public ChariteSlide(String newPicName, int newWidth, int newHeight)
            : base(newPicName, newWidth, newHeight)
        {
            setServerURL(ChariteConstants.chariteUrl_pure);
        }

        /// <summary>
        /// Liefert nur den Dateinamen ohne den Ordnernamen 
        /// </summary>
        /// <returns>der Dateiname Z.b aus /ISC2012/Hamamatsu/High-Throughput_40x/B-M-A-28-03-40x.ndpi wird B-M-A-28-03-40x.ndpi</returns>
        public String getshortSlideName()
        {
            String shortslidename = getPicName();

            string[] split = shortslidename.Split(new Char[] { '/' });

            return split[split.Length - 1];
        }

        /// <summary>
        /// Intialisiert das Slide. 
        /// </summary>
        public override String InitializeSlide(double viewfildwidth, double viewfildheight)
        {
            //Seitenverhältnisse berechnen
            targetRatio_WH = viewfildwidth / viewfildheight;
            targetRatio_HW = viewfildheight / viewfildwidth;
            slideRatio_WH = (double)getWidth() / (double)getHeight();
            slideRatio_HW = (double)getHeight() / (double)getWidth();

            //Je nach Seitenverhältnis Initialisieren
            if (targetRatio_HW < slideRatio_HW)
            {
                scrh = (int)viewfildheight;
                scrw = (int)(scrh * slideRatio_WH);
            }
            else if (targetRatio_HW > slideRatio_HW)
            {
                scrw = (int)viewfildwidth;
                scrh = (int)(scrw * slideRatio_HW);
            }
            else
            {
                scrh = (int)viewfildheight;
                scrw = (int)viewfildwidth;
            }

            //Das ganze Slide soll angezeigt werden also volle Breite und Höhe. Außerdem die Postition auf 0/0 gesetzt
            slidew = getWidth();
            slideh = getHeight();
            posX = 0;
            posY = 0;
            return getManipulatedUrl();
        }

        /// <summary>
        /// Liefert die vollständige URL mit zusätzlichen Abfrageparametern z.B. scrh usw. 
        /// </summary>
        /// <returns></returns>
        public override String getManipulatedUrl()
        {
            String url = getfullUrl() + "?posx=" + posX + "&posy=" + posY + "&slidew=" + slidew + "&slideh=" + slideh + "&scrw=" + scrw + "&scrh=" + scrh;
            return url;
        }
        /// <summary>
        /// Stellt ein Pan dar. Siehe: http://en.wikipedia.org/wiki/Multi-touch  
        /// </summary>
        /// <param name="PosStart">die Position von wo angefangen wird</param>
        /// <param name="PosEnd">die Endpostion</param>

        //todo: zoomstep einbeziehen da so kein realistisches bewegungsverhältnis
        public override void pan(Point posStart, Point posEnd)
        {
            //zurückgelegte Strecke auf dem Sichtbereich in Pixelwerte
            double targetShiftXValue = posStart.X - posEnd.X;
            double targetShiftYValue = posStart.Y - posEnd.Y;

            //Verhältnisumrechung in %
            double ratioShiftX = (targetShiftXValue / (double)scrw) * 100.0;
            double ratioShiftY = (targetShiftYValue / (double)scrh) * 100.0;

            //Absolute Bewegung im Slide in Pixelwerte
            double slideShiftXValue = (ratioShiftX / 100.0) * slidew;
            double slideShiftYValue = (ratioShiftY / 100.0) * slideh;

            if ((posX + slidew + slideShiftXValue) > getWidth())
            {
                posX = getWidth() - slidew;
            }
            else if ((posX + slideShiftXValue) < 0)
            {
                posX = 0;
            }
            else
            {
                posX = posX + (int)slideShiftXValue;
            }

            if ((posY + slideh + slideShiftYValue) > getHeight())
            {
                posY = getHeight() - slideh;
            }
            else if ((posY + slideShiftYValue) < 0)
            {
                posY = 0;
            }
            else
            {
                posY = posY + (int)slideShiftYValue;
            }
        }



        /// <summary>
        /// Überprüft ob ein PAN im Slide in X Richtung überhaupt möglich ist oder ob die Grenze des Slides schon erreicht ist
        /// </summary>
        /// <param name="deltaX">die e.Delta verschiebung auf der X Achse</param>
        /// <returns></returns>
        public override Boolean xTransPossible(double deltaX)
        {
            Boolean returnvalue = false;
            if (deltaX > 0 && posX > 0)
            {//delta ist negativ(linksverschiebung), posX ist innerhalb des Slides
                returnvalue = true;
            }
            else if (deltaX < 0 && posX + slidew < getWidth())
            {//delta ist postiv(rechtverschiebung), posX ist innerhalb des Slides
                returnvalue = true;
            }

            return returnvalue;
        }

        /// <summary>
        /// Überprüft ob ein PAN im Slide in Y Richtung überhaupt möglich ist oder ob die Grenze des Slides schon erreicht ist
        /// </summary>
        /// <param name="deltaX">die e.Delta verschiebung auf der Y Achse</param>
        public override Boolean yTransPossible(double deltaY)
        {
            Boolean returnvalue = false;
            if (deltaY > 0 && posY > 0)
            {
                returnvalue = true;
            }
            else if (deltaY < 0 && posY + slideh < getHeight())
            {
                returnvalue = true;
            }

            return returnvalue;
        }

        /// <summary>
        /// noch nicht Implementiert
        /// </summary>
        /// <param name="skale"></param>
        /// <returns></returns>
        public override Boolean zoomPossible(float skale)
        {
            if (slideh / skale > getHeight() && slidew / skale > getWidth())
                return false;
            return true;
        }

        /// <summary>
        /// Zoom in das Bild hinein. Zoom wird bei Touchgeräten mit dem Zeigerfinger und Daumen realisert.       
        /// </summary>
        /// 
        public override void zoom(double skaleX, double skaleY)
        {
            //Aktuelle Auflösung abfragen abzüglich des Topmenüs
            double viewfildwidth = (Window.Current.Bounds.Width);
            double viewfildheight = (Window.Current.Bounds.Height - 140);

            double newScrh = scrh * skaleY;
            double newScrw = scrw * skaleX;

            if (newScrh > viewfildheight && newScrw > viewfildwidth)
            {//Fall 1: Das Slide würde oben und unten über das Viewfield laufen daher müssen slidew&slideh bearbeitet werden scrw&srch müssen auf max gesetzt werden
                //Mmaximal erlaube Höhe setzen 
                scrh = (int)viewfildheight;
                scrw = (int)viewfildwidth;

                //neuen Wert für slideh bestimmen(gekürzt um den überstehenden bereich)
                int newSlideh = (int)(((double)scrh / newScrh) * (double)slideh);
                int newSlidew = (int)(((double)scrw / newScrw) * (double)slidew);

                //neue PosY setzten (mittig)
                posY = (int)(posY + ((slideh - newSlideh) / 2));
                posX = (int)(posX + ((slidew - newSlidew) / 2));

                slideh = newSlideh;
                slidew = newSlidew;
            }
            else if (newScrh > viewfildheight && newScrw < viewfildwidth)
            {//Fall 2:hochformat vergrößern - es muss oben und unten abgeschnitten werden 
                //Mmaximal erlaube Höhe setzen
                scrh = (int)viewfildheight;

                //neuen Wert für slideh bestimmen(gekürzt um den überstehenden bereich)
                int newSlideh = (int)(( (double)scrh / newScrh ) * (double)slideh);

                //neue PosY setzten (mittig)
                posY = (int)(posY + ((slideh - newSlideh) / 2));
                posX = 0;

                //Variablen setzen, slidew bleibt gleich
                scrw = (int)newScrw;
                slideh = newSlideh;
            }
            else if (newScrh < viewfildheight && newScrw > viewfildwidth)
            { //Fall 3: Querformat vergrößern - es muss links und rechts abgeschnitten werden
                scrw = (int)viewfildwidth;

                int newSlidew = (int)(((double)scrw / newScrw) * (double)slidew);

                posX = (int)(posX + ((slidew - newSlidew) / 2));
                posY = 0;

                //Variablen setzen, slideh bleibt gleich
                scrh = (int)newScrh;
                slidew = newSlidew;
            }
            else if (newScrw < viewfildwidth && newScrh < viewfildheight)
            {//Fall 4: Beim herraus zoomen muss an das Slide mehr Information angefügt werden

                //Bestimmen des neu anzuzeigenen Bereiches des Slides

                //neuen Wert für slideh bestimmen(gekürzt um den überstehenden bereich)
                int newSlideh = (int)(((double)scrh / newScrh) * (double)slideh);
                int newSlidew = (int)(((double)scrw / newScrw) * (double)slidew);

                //Fall41: es ist noch genügend Slidefläche für zoom out übrig/angeforderte Höhe und breite sind noch innerhalb des Slides
                if(newSlideh <= getHeight() && newSlidew <= getWidth())
                {
                    //neue PosXY setzten (mittig)
                    posY = (int)(posY + ((slideh - newSlideh) / 2));
                   posX = (int)(posX + ((slidew - newSlidew) / 2));

                    slideh = newSlideh;
                    slidew = newSlidew;
                }

                //Fall42: angeforderte Breite ist nicht mehr im Slide verfügbar (Anpassung scrw und slidew)
                else if(newSlidew > getWidth() && newSlideh <= getHeight())
                {
                    //das neue Slidew auf den max. verfügbare Slidebreite setzten
                    newSlidew = getWidth();
                    
                    //Anhand des neuen Seitenverhältnisses das neue scrw berechnen und setzen 
                    scrw = (int)((double)scrh * ((double)newSlidew / (double) newSlideh));

                    //Positionen von XY neu setzen
                    posX = 0; //da max. Breite dargestellt
                 //   posY = (int)(posY + ((slideh - newSlideh) / 2));
                    
                }

                //Fall43: angeforderte Höhe ist nicht mehr im Slide verfügbar (Anpassung scrh und slideh)
                else if (newSlideh > getHeight() && newSlidew <= getWidth())
                {
                    //das neue Slideh auf den max. verfügbare Slidehöhe setzten
                    newSlideh = getHeight();

                    //Anhand des neuen Seitenverhältnisses das neue scrh berechnen und setzen
                    scrh = (int)((double)scrw * ((double)newSlideh / (double)newSlidew));

                    //Positionen von XY neu setzen
                    posY = 0; //da schon max. Höhe dargestellt
                 //   posX = (int)(posX + ((slidew - newSlidew) / 2));
                }

                //Fall44: angeforderte Höhe und Breite ist nicht mehr im Slide verfügbar (Lades des Slides in voller Übersichtsgröße) 
                else if(newSlideh > getHeight() && newSlidew > getWidth())
                {
                    InitializeSlide(viewfildwidth, viewfildheight);
                }
            }

        }


    }
}
